package com.zmn.brs.business.impl.order;

import com.alibaba.fastjson.JSONObject;
import com.github.ltsopensource.core.json.JSON;
import com.zmn.brs.business.impl.base.BaseBServiceImpl;
import com.zmn.brs.business.interfaces.dingtalk.DingTalkBService;
import com.zmn.brs.business.interfaces.order.OrderComparisonBService;
import com.zmn.brs.business.interfaces.rule.AlarmRuleBService;
import com.zmn.brs.common.constant.BrsConst;
import com.zmn.brs.common.constant.RedisKeyConst;
import com.zmn.brs.common.enums.SceneTypeEnum;
import com.zmn.brs.dubbo.constant.DubboConsts;
import com.zmn.brs.model.bo.rule.CacheThresholdBO;
import com.zmn.brs.model.bo.rule.CustomRuleBO;
import com.zmn.brs.model.entity.record.EventRecord;
import com.zmn.brs.model.query.rule.OrderRuleCustomQuery;
import com.zmn.brs.model.vo.rule.ComparisonRuleVO;
import com.zmn.brs.model.vo.rule.common.OrderRuleVO;
import com.zmn.brs.services.interfaces.record.EventRecordService;
import com.zmn.brs.utils.BrsUtil;
import com.zmn.common.dto2.ReportDTO;
import com.zmn.common.utils.date.DateUtil;
import com.zmn.common.utils.string.StringUtil;
import com.zmn.consts.GlobalConsts;
import com.zmn.cube.common.dto.board.BoardConfigDIO;
import com.zmn.cube.common.dto.board.query.OrderBoardQueryDIO;
import com.zmn.cube.dubbo.dto.BoardCustomDIO;
import com.zmn.cube.dubbo.interfaces.board.BoardRemoteService;
import com.zmn.plat.common.dictionary.StatusEnum;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.Reference;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * 描述： 订单人单比接口实现
 *
 * @author chongw
 * @since 2021-06-28 9:55
 */
@Slf4j
@Service
public class OrderComparisonBServiceImpl extends BaseBServiceImpl<OrderRuleVO> implements OrderComparisonBService {

    final static String TAG = "订单监控人单比实现";

    @Resource
    private EventRecordService eventRecordService;

    @Reference(version = DubboConsts.INTERFACE_VERSION, check = false)
    BoardRemoteService boardRemoteService;

    @Resource
    private AlarmRuleBService alarmRuleBService;

    @Resource
    private DingTalkBService dingTalkBService;

    @Resource
    private RedisTemplate redisTemplate;

    /**
     * 计算当天人单比
     * @param eventType
     * @return
     */
    @Override
    public Boolean compute(Integer eventType){
        //生成临时版本号
        Integer versionNO = UUID.randomUUID().toString().hashCode();
        try {
            OrderRuleCustomQuery query = OrderRuleCustomQuery.builder()
                    .eventType(eventType)
                    .build();
            //获取人单比配置列表
            List<CustomRuleBO> comparisonRuleList =  alarmRuleBService.listOrderRuleByEventQuery(query);
            //获取公共阈值 - 预警百分比
            Double percentValue = getCommonThresholdValue(eventType);
            Double ratioValue = percentValue/100;

            comparisonRuleList.stream().forEach(o -> {
                //判断状态是否停用
                if(StatusEnum.DISABLE.getCode().equals(o.getRealStatus())){
                    log.error("[{}],规则ID：{}，状态已被停用！！！", TAG, o.getRuleId());
                    return;
                }
                //人单比对象
                ComparisonRuleVO configData = JSONObject.parseObject(o.getThresholdValue(), ComparisonRuleVO.class);
                //获取城市ID
                Integer cityId = configData.getCityId();
                //获取产品组ID
                Integer servGroupId = configData.getServGroupId();
                //获取人单比
                Map<String, Object> data =  this.getComparisonByCube(cityId, servGroupId);
                if(data == null || (data != null && data.isEmpty())){
                    log.error("[{}],版本号：{}, 调用cube无数据", TAG , versionNO);
                    return;
                }
                //获取实际值
                Object objValue = data.get(BrsUtil.buildKey(BrsConst.CUBE_COMPARISON_MEASURE_ID.toString()));
                if(objValue == null){
                    log.error("[{}],版本号：{}, 调用cube 人单比值为空！！！", TAG, versionNO);
                    return;
                }
                //去除格式符
                String strValue = objValue.toString().replace("%","").replace(",","");
                BigDecimal decimal = new BigDecimal(strValue);
                //获取实际值
                Double realValue = decimal.doubleValue();

                //缓存推送数据redis key
                String todayRedisKey = RedisKeyConst.getTodayRedisKey(eventType, DateUtil.getNowFormatted(DateUtil.FORMAT_DATE2));
                redisTemplate.opsForHash().put(todayRedisKey, String.format("%s-%s", cityId, servGroupId), realValue);
                redisTemplate.expire(todayRedisKey , 3 , TimeUnit.DAYS);
                //获取配置人单比阈值
                Double thresholdValue =  configData.getValue();
                //预警值= 人单比阈值* 预警百分比
                Double warnValue = thresholdValue * ratioValue;
                if(realValue >= warnValue){
                    log.info("[{}],版本号：{}, cityId：{}, servGroupId：{}，规则ID：{} 已触发订单人单比监控预警！实际值：{}，阈值：{}，预警百分比：{}", TAG, versionNO, cityId, servGroupId,
                            configData.getRuleId(), realValue, thresholdValue, percentValue);
                    JSONObject expandJson = new JSONObject();
                    expandJson.put("realValue", realValue);
                    expandJson.put("thresholdValue", thresholdValue);
                    expandJson.put("percentValue", percentValue);
                    EventRecord record = EventRecord.builder()
                            .objectId(o.getRuleId().longValue())
                            .thresholdId(o.getThresholdId())
                            .sceneType(SceneTypeEnum.ORDER_TARGET.getTypeId())
                            .eventCode(o.getEventCode())
                            .messageSend(GlobalConsts.NO)
                            .realName(o.getRuleName())
                            .expand(expandJson.toJSONString())
                            .createTime(DateUtil.getNow())
                            .monitorVersion(versionNO.toString())
                            .build();
                    //保存事件监控数据
                    Integer flag = eventRecordService.insert(record);
                    if (flag > 0) {
                        log.info("[{}],版本号：{}, cityId：{}，保存事件记录成功！！！", TAG, versionNO, cityId);
                    } else {
                        log.error("[{}],版本号：{}, cityId：{}，保存事件记录失败！！！", TAG, versionNO, cityId);
                    }
                }
            });
            //推送钉钉群消息
            this.pushJob(eventType);

            return true;
        }catch (Exception e){
            log.error("[{}],版本号：{}，人单比监控异常，异常信息：", TAG, versionNO, e);
        }
        return false;
    }


    /**
     * 推送钉钉群机器人
     * @param eventType
     */
    public void pushJob(Integer eventType){
        Integer robotId = this.getRobotId(eventType);
        if(robotId == null){
            log.error("[{}], eventType：{}，未配置钉钉预警群消息机器人！！！", TAG, eventType);
            return;
        }
        //缓存推送数据redis key
        String warnRedisKey = RedisKeyConst.getTodayRedisKey(eventType, DateUtil.getNowFormatted(DateUtil.FORMAT_DATE2));
        //获取预警数据
        Map<Object, Object> warnData = Optional.ofNullable(redisTemplate.opsForHash().entries(warnRedisKey)).orElse(new HashMap<>());
        StringBuffer sb = new StringBuffer();
        Map<Object, Object> sortMap = new TreeMap<>(new Comparator<Object>(){
            @Override
            public int compare(Object o1, Object o2) {
                return o1.toString().compareTo(o2.toString());
            }
        });
        sortMap.putAll(warnData);
        //遍历排序数据
        sortMap.forEach((k ,v) -> {
            String[] key = k.toString().split("-");
            Integer cityId = Integer.parseInt(key[0]);
            Integer servGroupId = Integer.parseInt(key[1]);
            //获取唯一key
            String cacheRedisKey = RedisKeyConst.getCacheRuleConfigRedisKey(eventType,cityId ,servGroupId);
            //获取城市阈值配置
            CacheThresholdBO configData = this.getRuleConfigValue(cacheRedisKey);
            if(configData == null){
                return;
            }
            Double realValue = Double.parseDouble(v.toString());
            //阈值
            Double thresholdValue = configData.getValue();
            //获取公共阈值 - 预警百分比
            Double percentValue = this.getCommonThresholdValue(eventType);
            Double ratioValue = percentValue/100;
            //预警值= 人单比阈值* 预警百分比
            Double warnValue = thresholdValue * ratioValue;
            if (realValue >= warnValue) {
                ComparisonRuleVO vo = JSONObject.parseObject(configData.getThresholdValue(), ComparisonRuleVO.class);
                sb.append(String.format("「%s.%s-%s」实际人单比 %s", vo.getProvinceName(), vo.getCityName() , vo.getServGroupName() , realValue));
                sb.append("\n");
            }
        });
        if(sb != null && StringUtil.isNotBlank(sb.toString())){
            //获取公共阈值 - 预警百分比
            String percentValueStr = BrsUtil.formatDoubleToStr(getCommonThresholdValue(eventType));
            sb.insert(0, String.format("以下各城市产品组人单比已在峰值的%s%s以上，请时刻关注！\n", percentValueStr, "%"));
            sb.insert(0,"【人单比预警】\n");
            sb.append(String.format("%s数据", DateUtil.getNowFormatted().replace(" ", " 截止 ")));
            //发送钉钉群消息
            dingTalkBService.sendDingtalkGroup(robotId, sb.toString());
        }
    }

    /**
     * 获取对应城市，产品组 人单比实际值
     * @param cityId
     * @param servGroupId
     * @return
     */
    protected Map<String, Object> getComparisonByCube(Integer cityId , Integer servGroupId){
        String today = DateUtil.getNowFormatted(DateUtil.FORMAT_DATE3);
        BoardCustomDIO dio = new BoardCustomDIO();
        OrderBoardQueryDIO boardQueryDIO = new OrderBoardQueryDIO();
        boardQueryDIO.setCityId(cityId);
        boardQueryDIO.setServGroupId(servGroupId);
        boardQueryDIO.setTimeRange(String.format("%s - %s", today, today));
        dio.setBoardQueryDIO(boardQueryDIO);
        dio.setDatasetId(BrsConst.CUBE_COMPARISON_DATASET_ID);
        BoardConfigDIO boardConfigDIO = new BoardConfigDIO();
        boardConfigDIO.setMeasureIds(Arrays.asList(BrsConst.CUBE_COMPARISON_MEASURE_ID));
        boardConfigDIO.setDebug(true);
        dio.setBoardConfigDIO(boardConfigDIO);
        log.info("[{}],cube 入参：{}", TAG, JSON.toJSONString(dio));
        try {
            ReportDTO<Map<String, Object>> report = boardRemoteService.getCustomReport(dio);
            log.info("[{}],cube响应状态：{}, 响应数据：{}", TAG , report.isSuccess() , JSON.toJSONObject(report));
            return report.getTotalRow();
        }catch (Exception e){
            log.error("[{}], 调用cube获取产品组人单比数据异常，异常信息：", TAG , e);
        }
        return new HashMap<>();
    }
}
